﻿#if SILVERLIGHT || MONODROID || __IOS__
#define USELEGACYDIALOGS
#endif

#region File and License Information
/*
<File>
	<License>
		Copyright © 2009 - 2017, Daniel Vaughan. All rights reserved.
		This file is part of Calcium (http://calciumsdk.net), 
		which is released under the MIT License.
		See file /Documentation/License.txt for details.
	</License>
	<CreationDate>2009-04-25 14:43:57Z</CreationDate>
</File>
*/
#endregion

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

using Outcoder.Services.DialogService;

namespace Outcoder.Services.Implementation
{
	/// <summary>
	/// Base implementation of <see cref="IDialogService"/>.
	/// </summary>
	public abstract class DialogServiceBase : IDialogService
	{
		public Func<string> DefaultMessageCaptionFunc { get; set; }
		public Func<string> DefaultQuestionCaptionFunc { get; set; }
		public Func<string> DefaultWarningCaptionFunc { get; set; }
		public Func<string> DefaultErrorCaptionFunc { get; set; }

		protected int openDialogCount;

		public bool DialogOpen
		{
			get
			{
				return openDialogCount > 0;
			}
		}

		/*TODO: implement a means to modify the user MessageImportance threshold value. 
		 * This be done by subscribing to a composite property changed event. */
		public static DialogImportance MinumumImportance { get; protected set; }

		static DialogServiceBase()
		{
			MinumumImportance = DialogImportance.Low;
		}

		/// <summary>
		/// Shows a dialogue using a known set of buttons and images. 
		/// Override this message in test mocks.
		/// This is the only place where a MessageBox is shown.
		/// </summary>
		/// <param name="body">The message text to display.</param>
		/// <param name="expandableDetails">Can be <code>null</code>. 
		/// A detailed message that is display in a hidden area of the dialog, 
		/// and revealed on user request.</param>
		/// <param name="caption">The caption to display at the top of the dialog.</param>
		/// <param name="dialogButton">The message box button enum value, 
		/// which determines what buttons are shown.</param>
		/// <param name="dialogImage">The message box image, 
		/// which determines what icon is used.</param>
		/// <param name="importanceThreshold">The minimum filter level 
		/// that a user must have in order to receive the message.</param>
		/// <param name="completeAction">The action that is called when the dialog is closed.</param>
		/// <returns>The result of showing the message box.</returns>
		public abstract Task<DialogResult> ShowDialogAsync(
								object content, 
								string caption, 
								DialogButton dialogButton,
								DialogImage dialogImage = DialogImage.None,
								DialogImportance importanceThreshold = DialogImportance.High, 
								object details = null,
								DialogController dialogController = null);
		#region Messages

		protected string GetDefaultMessageCaption()
		{
			/* TODO: Make localizable resource. */
			string defaultCaption = DefaultMessageCaptionFunc != null
										? DefaultMessageCaptionFunc() : "Message";
			return defaultCaption;
		}
		//		public void ShowMessage(string message, MessageImportance importanceThreshold)
		//		{
		//			ShowMessage(message, null, importanceThreshold);
		//		}

		//		public void ShowMessage(string message, string caption = null, MessageImportance importanceThreshold = MessageImportance.High)
		//		{
		//			ShowMessage(message, caption, importanceThreshold, null);
		//		}

		public async Task ShowMessageAsync(
			string message,
			string caption = null,
			DialogImportance importanceThreshold = DialogImportance.High,
			object expandableDetails = null)
		{
			await ShowDialogAsync(message, caption,
				DialogButton.OK, DialogImage.Information, importanceThreshold, expandableDetails);
		}
		#endregion

		#region Warnings
		string GetDefaultWarningCaption()
		{
			/* TODO: Make localizable resource. */
			string defaultCaption = DefaultWarningCaptionFunc != null
										? DefaultWarningCaptionFunc() : "Warning";
			return defaultCaption;
		}

		public async Task ShowWarningAsync(string message, string caption = null, object expandableDetails = null)
		{
			await ShowDialogAsync(message, caption ?? GetDefaultWarningCaption(),
				DialogButton.OK, DialogImage.Warning, DialogImportance.High, expandableDetails);
		}
		#endregion

		#region Errors
		string GetDefaultErrorCaption()
		{
			/* TODO: Make localizable resource. */
			string defaultCaption = DefaultErrorCaptionFunc != null
										? DefaultErrorCaptionFunc() : "Error";
			return defaultCaption;
		}

		public async Task ShowErrorAsync(string message, string caption = null, object expandableDetails = null)
		{
			await ShowDialogAsync(message, caption ?? GetDefaultErrorCaption(),
				DialogButton.OK, DialogImage.Error, DialogImportance.High, expandableDetails);
		}
		#endregion

		#region Questions

		string GetDefaultQuestionCaption()
		{
			/* TODO: Make localizable resource. */
			string defaultCaption = DefaultQuestionCaptionFunc != null
										? DefaultQuestionCaptionFunc() : "Question";
			return defaultCaption;
		}

		public async Task<bool> AskYesNoQuestionAsync(string question, string caption = null, object expandableDetails = null)
		{
			var messageBoxResult = await ShowDialogAsync(question, caption ?? GetDefaultQuestionCaption(),
				DialogButton.YesNo, DialogImage.Question, DialogImportance.High, null);
			return messageBoxResult == DialogResult.Yes
				|| messageBoxResult == DialogResult.OK;
		}

		public async Task<bool> AskOkCancelQuestionAsync(string question, string caption = null, object expandableDetails = null)
		{
			var messageBoxResult = await ShowDialogAsync(question, caption ?? GetDefaultQuestionCaption(),
				DialogButton.OKCancel, DialogImage.Question, DialogImportance.High, null);
			return messageBoxResult == DialogResult.OK
				|| messageBoxResult == DialogResult.Yes;
		}
		
		public abstract Task<QuestionResponse<TResponse>> AskQuestionAsync<TResponse>(
			IQuestion<TResponse> question);

		public abstract Task<int?> ShowDialogAsync(
										object body, 
										IEnumerable<object> buttons, 
										string caption = null,
										int defaultAcceptButtonIndex = -1, 
										object expandableDetails = null,
										DialogController dialogController = null);

		//public abstract Task<TextResponse> AskQuestionWithTextResponse(
		//	TextResponseQuestion textResponseQuestion);
		
		public async Task<YesNoCancelQuestionResult> AskYesNoCancelQuestionAsync(string question, string caption = null, object expandableDetails = null)
		{
			DialogResult dialogResult = await ShowDialogAsync(question, caption ?? GetDefaultQuestionCaption(),
											DialogButton.YesNoCancel, DialogImage.Question, DialogImportance.High, expandableDetails);
			
			switch (dialogResult)
			{
				case DialogResult.Yes:
					return YesNoCancelQuestionResult.Yes;
				case DialogResult.No:
					return YesNoCancelQuestionResult.No;
				case DialogResult.Cancel:
					return YesNoCancelQuestionResult.Cancel;
				default:
					/* Should never get here. */
					throw new InvalidOperationException("Invalid dialog MessageBoxResult."); /* TODO: Make localizable resource. */
			}
		}

		#endregion

#if WINDOWS_PHONE || WINDOWS_UWP || __ANDROID__
		public abstract Task<object> ShowToastAsync(ToastParameters toastParameters);

		public async Task<object> ShowToastAsync(string caption, string body = null)
		{
			return await ShowToastAsync(new ToastParameters() { Caption = caption, Body = body});
		}
#endif

#if __ANDROID__ || MONODROID
		public Android.Content.Context Context { protected get; set; }

		public int DialogStyle { get; set; } = Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Lollipop
					? Android.Resource.Style.ThemeMaterialDialogAlert : -1;
						//Theme_Material_Light_Dialog_Alert
#endif
	}
}
